﻿using System;
//using System.Drawing;
using MyCraft.Minecraft_2D.Blocs;
using Microsoft.Xna.Framework;
using System.Runtime.Serialization;
using System.Collections;
using System.Collections.Generic;

namespace MyCraft.Minecraft_2D
{
    [DataContract]
    public class Block
    {
        #region Attributs
        private TypeBloc _type;
        private Bloc _bloc;
        [IgnoreDataMember]
        private Block _top;
        [IgnoreDataMember]
        private Block _bottom;
        [IgnoreDataMember]
        private Block _left;
        [IgnoreDataMember]
        private Block _right;
        private Point _position;
        private static Map _map;
        private bool _isNew, _isSun;
        private int _light;
        private bool _newLight;
        #endregion

        #region Constructeur
        public Block()
        {
            _top = null;
            _bottom = null;
            _left = null;
            _right = null;
            _isNew = true;
            _isSun = false;
            _newLight = false;
            _type = TypeBloc.Air;
            _bloc = BlocSet.GetSingleton()[Type];
            _light = 0;
        }
        #endregion

        #region Proprietés
        public TypeBloc Type
        {
            get { return this._type; }
            set
            {
                this._type = value;
                if (_bloc.Id != (int)Type)
                    _bloc = BlocSet.GetSingleton()._newBlocs[Type](new Vector2(0.5f), 0);
            }
        }

        internal Bloc Bloc
        {
            get { return _bloc; }
            set
            {
                _bloc = value;
                if (Type != (TypeBloc)_bloc.Id)
                    Type = (TypeBloc)_bloc.Id;
            }
        }

        public Block Bottom
        {
            get { return _bottom; }
            set { _bottom = value; }
        }

        public Block Left
        {
            get { return _left; }
            set { _left = value; }
        }

        public Block Right
        {
            get { return _right; }
            set { _right = value; }
        }

        public Block Top
        {
            get { return this._top; }
            set { this._top = value; }
        }

        public bool IsNew
        {
            get { return _isNew; }
            set { _isNew = value; }
        }

        public bool IsSun
        {
            get { return _isSun; }
            set { _isSun = value; }
        }

        public bool NewLight
        {
            get { return _newLight; }
            set { _newLight = value; }
        }

        public int Light
        {
            get { return _light; }
            set
            {
                _light = (int)MathHelper.Clamp(value, 0, 100);
            }
        }

        public Point Position
        {
            get { return this._position; }
            set { this._position = value; }
        }

        public static Map Map
        {
            get { return Block._map; }
            set { Block._map = value; }
        }
        #endregion

        #region Methodes
        public IEnumerable<Block> Ligne(Direction direction, int lenght)
        {
            Block b = this;
            if (direction == Direction.Up)
                for (int i = 0; i < lenght && b.Top != null; i++)
                {
                    b = b.Top;
                    yield return b;
                }
            else if (direction == Direction.Down)
                for (int i = 0; i < lenght && b.Bottom != null; i++)
                {
                    b = b.Bottom;
                    yield return b;
                }
            else if (direction == Direction.Left)
                for (int i = 0; i < lenght && b.Left != null; i++)
                {
                    b = b.Left;
                    yield return b;
                }
            else 
                for (int i = 0; i < lenght && b.Right != null; i++)
                {
                    b = b.Right;
                    yield return b;
                }
            yield break;

            //int start;
            //if (direction == Direction.Up)
            //    for (start = b._position.Y - 1; start > start - lenght && Map.Exist(new Point(b._position.X, start)); start--)
            //    {
            //        yield return Map[new Point(b._position.X, start)];
            //    }
            //else if (direction == Direction.Down)
            //    for (start = b._position.Y + 1; start < start + lenght && Map.Exist(new Point(b._position.X, start)); start++)
            //    {
            //        yield return Map[new Point(b._position.X, start)];
            //    }
            //else if (direction == Direction.Left)
            //    for (start = b._position.X - 1; start < start - lenght && Map.Exist(new Point(start, b._position.Y)); start--)
            //    {
            //        yield return Map[new Point(b._position.X, start)];
            //    }
            //else
            //    for (start = b._position.X + 1; start > start + lenght && Map.Exist(new Point(start, b._position.Y)); start++)
            //    {
            //        yield return Map[new Point(b._position.X, start)];
            //    }
            //yield break;
        }

        public IEnumerable<Block> Around()
        {
            if (Top != null)
                yield return Top;
            if (Left != null)
                yield return Left;
            if (Bottom != null)
                yield return Bottom;
            if (Right != null)
                yield return Right;
            yield break;
        }

        public void Refresh(int i = 0)
        {
            ++i;

            if (Top == null && Type == TypeBloc.Air)
                IsSun = true;
            else if (Type == TypeBloc.Air)
                IsSun = Top.IsSun;
            else
                IsSun = false;

            int newLight;

            if (IsSun)
                newLight = 100;
            else
            {
                newLight = 0;
                foreach (Block b in Around())
                    newLight = Math.Max(newLight, b._light + b._bloc._light);
            }

            if (newLight == Light && i > 1)
                return;
            Light = newLight;

            foreach (Block b in Around())
                b.Refresh(i);
        }

        public void Update(double timer)
        {
            this.Bloc = Bloc.Update(this, timer);
            this.Bloc = _bloc.OnLife(timer);
            Refresh();
        }

        public override string ToString()
        {
            return "{" + Type.ToString() + ", " + Position.ToString() + "}";
        }
        #endregion

        #region Cast
        public static implicit operator TypeBloc(Block b)
        {
            return b.Type;
        }
        #endregion
    }
}
